using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;

namespace Salesman
{
    public class LibFile : IDisposable
    {

        private readonly Dictionary<string, string> _properties = new Dictionary<string, string>();
        private readonly List<DataSection> _dataSections = new List<DataSection>();
        private string _nextDataSectionName;
        private FileTypes _fileType = FileTypes.Unknown;
        private StreamReader _reader = null;

        void Load(StreamReader reader)
        {
            _dataSections.Clear();
            _properties.Clear();

            while (true)
            {
                string line = reader.ReadLine();
                if (line == null)
                    break;
                string[] split = line.Split(':');
                string begin = split[0].Trim();
                if (split.Length > 1)
                {
                    string end = split[1].Trim();
                    if (_properties.ContainsKey(begin))
                        _properties[begin] += Environment.NewLine + end;
                    else
                        _properties.Add(begin, end);
                }
                else if (split.Length > 0) // can be false!
                {
                    _nextDataSectionName = split[0];
                    break;
                }
            }
            _reader = reader;
            PostProcess();
        }
        void PostProcess()
        {
            switch (this["TYPE"])
            {
                case "TSP":
                    _fileType = FileTypes.TSPInstance;
                    break;
                case "TOUR":
                    _fileType = FileTypes.Tour;
                    break;
                default:
                    _fileType=FileTypes.Unsupported;
                    break;
            }
        }
        public string this[string key]
        {
            get
            {
                string value;
                _properties.TryGetValue(key, out value);
                return value ?? "";
            }
        }

        public static LibFile Load(string path)
        {
            StreamReader reader = File.OpenText(path);
            var file = new LibFile();
            file.Load(reader);
            return file;
        }

        public FileTypes FileType
        {
            get { return _fileType; }
        }

        public IEnumerable<DataSection> ReadDataSections()
        {
            yield return new DataSection
            {
                SectionName = _nextDataSectionName,
                Reader = _reader,
            };
        }
        public enum FileTypes
        {
            TSPInstance = 0,
            Tour = 1,
            Unsupported = 2,
            Unknown = 3
        }

        public class DataSection
        {
            private string _sectionName;
            private StreamReader _reader;

            public StreamReader Reader
            {
                get { return _reader; }
                internal set { _reader = value; }
            }

            public string SectionName
            {
                get { return _sectionName; }
                internal set { _sectionName = value; }
            }

            public IEnumerable<double[]> ReadData()
            {
                while (true)
                {
                    string line = Reader.ReadLine();
                    if (line == null)
                        yield break;
                    var strings = line.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries);
                    var values = new double[strings.Length];
                    for (int i = 0; i < values.Length; i++)
                    {
                        if (!double.TryParse(strings[i], NumberStyles.Float, CultureInfo.InvariantCulture, out values[i]))
                            yield break;
                    }
                    yield return values;
                }
            }
        }

        public void Dispose()
        {
            if (_reader != null)
            {
                _reader.Close();
                _reader = null;
            }
        }

        public IEnumerable<KeyValuePair<string, string>> Properties()
        {
            foreach (var property in _properties)
            {
                yield return property;
            }
        }
    }
}